#include <OgreRoot.h>
#include <OgreFrameListener.h>
#include <OgreConfigFile.h>
#include <OgreRenderWindow.h>
#include <OgreSceneManager.h>
//#include <CEGUI/CEGUI.h>
//#include <OgreCEGUIRenderer.h>

#include "application.h"
#include "SettingsManager.h"
#include "Camera.h"

using namespace Ogre;

//global variables
/**********************************************************************/
SettingsManager gSettings;
SceneManager* gSceneMgr;
OMGCamera* gCamera;
/**********************************************************************/





class EventListener : public FrameListener
{
public:
    EventListener(OIS::Keyboard *keyboard)
     : mKeyboard(keyboard)
    {
    }

    bool frameStarted(const FrameEvent& evt)
    {
        mKeyboard->capture();
        return !mKeyboard->isKeyDown(OIS::KC_ESCAPE);
    }

private:
    OIS::Keyboard *mKeyboard;
};




void Application::go()
{
    gSettings.parseSection("Bootstrap"); // get the boot specific variables
    createRoot();
    defineResources();
    setupRenderSystem();
    createRenderWindow();
    initializeResourceGroups();
    setupScene();
    setupInputSystem();
//        setupCEGUI();
    createFrameListener();
    startRenderLoop();
}

Application::~Application()
{
    mInputManager->destroyInputObject(mKeyboard);
    OIS::InputManager::destroyInputSystem(mInputManager);

    // delete mRenderer;
    // delete mSystem;

    delete mListener;
    delete mRoot;

}

void Application::createRoot()
{
    #if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    mRoot = new Root("cfg/plugins_win32d.cfg");
    #else
    mRoot = new Root("cfg/plugins_unix.cfg");
    #endif
}

void Application::defineResources()
{
    String secName, typeName, archName;
    ConfigFile cf;
    cf.load("cfg/resources.cfg");
    ConfigFile::SectionIterator seci = cf.getSectionIterator();
    while (seci.hasMoreElements())
    {
        secName = seci.peekNextKey();
        ConfigFile::SettingsMultiMap *settings = seci.getNext();
        ConfigFile::SettingsMultiMap::iterator i;
        for (i = settings->begin(); i != settings->end(); ++i)
        {
            typeName = i->first;
            archName = i->second;
            ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
        }
    }

}

void Application::setupRenderSystem()
{
    if (!mRoot->restoreConfig() && !mRoot->showConfigDialog())
        throw Exception(52, "User canceled the config dialog!", "Application::setupRenderSystem()");

/*
    // Do not add this to the application
    RenderSystem *rs = mRoot->getRenderSystemByName("Direct3D9 Rendering Subsystem");
                                            // or use "OpenGL Rendering Subsystem"
    mRoot->setRenderSystem(rs);
    rs->setConfigOption("Full Screen", "No");
    rs->setConfigOption("Video Mode", "800 x 600 @ 32-bit colour");*/
}

void Application::createRenderWindow()
{
    mRoot->initialise(true, "omgwheel");
}

void Application::initializeResourceGroups()
{

    ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}

void Application::setupScene()
{
    gSceneMgr = mRoot->createSceneManager(ST_GENERIC, "Default SceneManager");
    gCamera=new OMGCamera();
    //Viewport *vp = mRoot->getAutoCreatedWindow()->addViewport(cam);
    mRoot->getAutoCreatedWindow()->addViewport(gCamera->mOgreCamera);

    mSession=new Session();
}

void Application::setupInputSystem()
{
    size_t windowHnd = 0;
    std::ostringstream windowHndStr;
    OIS::ParamList pl;
    RenderWindow *win = mRoot->getAutoCreatedWindow();

    win->getCustomAttribute("WINDOW", &windowHnd);
    windowHndStr << windowHnd;
    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
    mInputManager = OIS::InputManager::createInputSystem(pl);
    try
    {
        mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, false));
        mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, false));
    }
    catch (const OIS::Exception &e)
    {
        throw Exception(42, e.eText, "Application::setupInputSystem");
    }

}

void Application::setupCEGUI()
{
    //SceneManager *mgr = mRoot->getSceneManager("Default SceneManager");
    //RenderWindow *win = mRoot->getAutoCreatedWindow();

    // CEGUI setup
    //mRenderer = new CEGUI::OgreCEGUIRenderer(win, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mgr);
    //mSystem = new CEGUI::System(mRenderer);
}

void Application::createFrameListener()
{
    mListener = new EventListener(mKeyboard);
    mRoot->addFrameListener(mListener);
}

void Application::startRenderLoop()
{
    mRoot->startRendering();
}
